Skip to content

Range Utility

As we saw a couple of lessons ago, we can use .map to iterate over an array of data, to render 1 React element per item.

But what if we don't have an array?

For example, it's common for ratings to use a 5-star system. Let's suppose we want to render 0 to 5 little star icons, depending on the rating.

Spend a few minutes poking at the problem here. Your goal is to render n stars inside the StarRating component, where n is the value of rating:

Code Playground

function StarRating({ rating }) {
/*
Here's the markup for a single star:
<img
alt=""
className="gold-star"
src="https://sandpack-bundler.vercel.app/img/gold-star.svg"
/>
Your job is to repeat this element
based on the `rating` prop.
If the rating is 4, we need 4 copies.
*/
return (
<div className="star-wrapper">
</div>
);
}

export default StarRating;

This is a tricky problem!

Our default tool in JavaScript to do this sort of thing would be a for loop. As we've learned, though, for is a statement, and we can't use statements within our JSX.

Here's one solution: we can use a for loop above the JSX, to create our array of elements:

function StarRating({ rating }) {
let stars = [];
for (let i = 0; i < rating; i++) {
stars.push(
<img
key={i}
alt=""
className="gold-star"
src="https://sandpack-bundler.vercel.app/img/gold-star.svg"
/>
);
}
return (
<div className="star-wrapper">
{stars}
</div>
);
}

We create an array of image elements with a for loop, and then we render that array inside our JSX. As we saw with .map, React can “unpack” arrays for us, and render each of the elements inside, so long as we provide a unique key for each element.

A functional alternative

There's nothing wrong with this approach, but I have a preferred alternative: using a range function.

range is a utility function. It's not part of the JavaScript language (unfortunately), but it is a staple of utility libraries like lodash.

This is one of my favourite utilities. I use it in every project I work on (in fact, I've used it over 20 times in the codebase for this course platform!). I love it.

To understand how it works, let's look at some examples:

// Create an array from 0 (inclusive) to 2 (exclusive):
range(2);
// Produces: [0, 1]
// Create an array from 0 (inclusive) to 5 (exclusive):
range(5);
// Produces: [0, 1, 2, 3, 4]
// Create an array from 2 (inclusive) to 6 (exclusive):
range(2, 6);
// Produces: [2, 3, 4, 5]
// Create an array from 2 to 10, picking every 2nd number
range(2, 10, 2);
// Produces: [2, 4, 6, 8]

Essentially, it's the expression version of a “for” loop statement, like how && can be an expression version of an “if” statement. This means we can use it in our JSX.

Here's how we'd use it:

function StarRating({ rating }) {
return (
<div className="star-wrapper">
{range(rating).map((num) => (
<img
key={num}
alt=""
className="gold-star"
src="https://sandpack-bundler.vercel.app/img/gold-star.svg"
/>
))}
</div>
);
}

range(rating) will produce an array from 0 up to (but not including) n, where n is the supplied rating. Then, we use the .map trick we learned about to iterate over that array, creating a copy of our star image for each one.

For the key, we use the number generated within the array, since we know these numbers will be unique.

Range function code

Here's how the range function is defined:

const range = (start, end, step = 1) => {
let output = [];
if (typeof end === 'undefined') {
end = start;
start = 0;
}
for (let i = start; i < end; i += step) {
output.push(i);
}
return output;
};

Here's a complete solution demonstrating this function:

Code Playground

function StarRating({ rating }) {
return (
<div className="star-wrapper">
{range(rating).map((num) => (
<img
key={num}
alt=""
className="gold-star"
src="https://sandpack-bundler.vercel.app/img/gold-star.svg"
/>
))}
</div>
);
}

const range = (start, end, step = 1) => {
let output = [];

if (typeof end === 'undefined') {
end = start;
start = 0;
}

for (let i = start; i < end; i += step) {
output.push(i);
}

return output;
};

export default StarRating;

When relevant, this range function will be provided to you on this course platform.

In terms of using this in the real world, I like to create a utils.js file that collects this and other handy JS functions. You can also use the lodash “range” function from NPM.